package eu.boss.activities;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import Util.FinishListener;
import Util.Util;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListView;
import android.widget.TextView;
import eu.boss.R;
import eu.boss.controller.ShadowStatsController;
import eu.boss.http.Http;
import eu.boss.model.Player;

/**
 * Activity displayed on the second tabwidget. Contains a listview with a checkbox to select players
 * @author Arnaud
 *
 */
public class GameActivity extends Activity {

	/**
	 * @param UPDATE_STATS_ID ID of UpdateStatsActivity to recognize which activity returns a result
	 * @param mController Service used as MVC controller
	 * @param mMapper Mapper to map JSON data
	 * @param mLvPlayers ListView containing datas
	 * @param mCheckedState Array containing checkbox states
	 * @param mControllerConnection Connection with the service 
	 */
	private static int UPDATE_STATS_ID = 3;
	private ShadowStatsController mController;
	private ObjectMapper mMapper = new ObjectMapper();
	private ListView mLvPlayers;
	private boolean[] mCheckedState;
	
	private ServiceConnection mControllerConnection = new ServiceConnection() {
		// Called when the connection with the service is established
		public void onServiceConnected(ComponentName className, IBinder service) {
			mController = ((ShadowStatsController.LocalBinder) service)
					.getService();
			initiate();
		}

		// Called when the connection with the service disconnects unexpectedly
		public void onServiceDisconnected(ComponentName className) {
			mController = null;
		}
	};
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.gamelist);
	}

	@Override
	protected void onStart() {
		super.onStart();
		// new intent to bind service
		Intent intent = new Intent(this, ShadowStatsController.class);
		getApplicationContext().bindService(intent, mControllerConnection,
				Context.BIND_AUTO_CREATE);
	}

	@Override
	protected void onResume() {
		super.onResume();
		//New boolean array. It's necessary because of the possibility to add or delete a player. The array must have the same size as players number
		//Then updating UI
		if (mController != null) {
			mCheckedState = new boolean[mController.getPlayersList().getPlayers().size()];
			updateList();
		}
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		//Intercepting when menu button is touched. Displaying UpdateStatsActivity
		if (keyCode == KeyEvent.KEYCODE_MENU) 
			startActivityForResult(new Intent(GameActivity.this,UpdateStatsActivity.class), UPDATE_STATS_ID);
		return super.onKeyDown(keyCode, event);
	}

	/**
	 * Initialize components
	 */
	public void initiate() {
		mLvPlayers = (ListView) findViewById(R.id.lvGameListPlayers);
		mCheckedState = new boolean[mController.getPlayersList().getPlayers()
				.size()];
		updateList();
	}
	
	
	/**
	 * Update list with the adapter
	 */
	public void updateList() {
		GameAdapter adapter = new GameAdapter(this, mController
				.getPlayersList().getPlayers());
		mLvPlayers.setAdapter(adapter);
	}

	/**
	 * AsyncTask making HTTP Put request in a second thread. Updating server data
	 * 
	 * @author Arnaud
	 * 
	 */
	private class PlayersPutTask extends AsyncTask<Void, Void, String> {

		@Override
		protected String doInBackground(Void... params) {

			// PlayersListRequest 
			String url = getString(R.string.web_app_url);
			String response = null;
			Http request = new Http();

			try {
				//Creation of a pair Key/Value to put on the server and get response.
				String s = mMapper.writeValueAsString(mController.getPlayersList());
				ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
				pairs.add(new BasicNameValuePair("list", s));
				response = request.executePutRequest(url, pairs);

			} catch (JsonParseException e) {
				displayErrorMessage(e.toString());
			} catch (JsonMappingException e) {
				displayErrorMessage(e.toString());
			} catch (IllegalStateException e) {
				displayErrorMessage(e.toString());
			} catch (IOException e) {
				displayErrorMessage(e.toString());
			}
			return response;
		}

		@Override
		protected void onPostExecute(String result) {
			super.onPostExecute(result);
			updateList();
		}
	};

	/**
	 * Method launching server update. Error message displayed if no internet connection
	 */
	public void updateServer() {
		if (Util.isOnline(this)) {
			PlayersPutTask putTask = new PlayersPutTask();
			putTask.execute();
		} else
			displayErrorMessageAndFinish(getString(R.string.connection_error));
	}

	
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if ((requestCode == UPDATE_STATS_ID) && (resultCode == RESULT_OK)) {
			Bundle extras = data.getExtras();

			// We get 3 extras from UpdateStatsActivity. status=0:won; status=1: lost; team=0:shadow; team=1:hunter; team=2:neutral

			if (extras != null && extras.containsKey("gameStatus")) {
				int status = extras.getInt("gameStatus");
				int team = extras.getInt("team");
				int position;
				for (position = 0; position < mCheckedState.length; position++) {
					if (mCheckedState[position] == true) {
						switch (team) {
						case 0:
							if (status == 0)
								mController.getPlayersList().getPlayers()
										.get(position).incrementWS();
							else
								mController.getPlayersList().getPlayers()
										.get(position).incrementLS();
							break;

						case 1:
							if (status == 0)
								mController.getPlayersList().getPlayers()
										.get(position).incrementWH();
							else
								mController.getPlayersList().getPlayers()
										.get(position).incrementLH();
							break;

						case 2:
							if (status == 0)
								mController.getPlayersList().getPlayers()
										.get(position).incrementWN();
							else
								mController.getPlayersList().getPlayers()
										.get(position).incrementLN();
							break;
						default:
							break;
						}
					}
				}
				updateServer();
				updateList();
			}
		}
	}

	/**
	 *  A pretty basic ViewHolder used to keep references on children
	 *  
	 * @author Arnaud
	 *
	 */
	private static class ViewHolder {
		TextView tvName;
		TextView tvColor;
		CheckBox cbGame;
	}
	
	/**
	 * Adapter to fill the listview with custom items containing 2 textview and a checkbox.
	 * @author Arnaud
	 *
	 */
	private class GameAdapter extends BaseAdapter {

		private List<Player> players;
		Context context;

		public GameAdapter(Context c, List<Player> p) {
			players = p;
			context = c;
		}

		public int getCount() {
			return players.size();
		}

		public Object getItem(int position) {
			return players.get(position);
		}

		public long getItemId(int position) {
			return position;
		}
		

		/**
		 * This method fill every single item included in the listview
		 */

		public View getView(int position, View convertView, ViewGroup parent) {

			ViewHolder holder;

			if (convertView == null) {

				// initialize components
				convertView = getLayoutInflater().inflate(R.layout.listviewitemgame, null);
				holder = new ViewHolder();				
				holder.tvName = (TextView) convertView.findViewById(R.id.tvNameGame);
				holder.cbGame = (CheckBox) convertView.findViewById(R.id.checkBoxGame);
				holder.tvColor = (TextView) convertView.findViewById(R.id.tvColorGame);
				
				convertView.setTag(holder);

			} else {
				holder = (ViewHolder) convertView.getTag();
			}

			//to fix checkbox bug
			holder.cbGame.setOnCheckedChangeListener(null);
            holder.cbGame.setChecked(mCheckedState[position]);
            holder.cbGame.setOnCheckedChangeListener(mCheckedChanceChangeListener);
            
            // fill component
			holder.tvName.setText(players.get(position).getName());
			holder.tvColor.setBackgroundDrawable(context.getResources()
					.getDrawable(players.get(position).getColor()));
			return convertView;
		}
	}

	private OnCheckedChangeListener mCheckedChanceChangeListener = new OnCheckedChangeListener() {
		public void onCheckedChanged(CompoundButton buttonView,
				boolean isChecked) {
			// Keeping checkbox state in the array
			final int position = mLvPlayers.getPositionForView(buttonView);
			if (position != ListView.INVALID_POSITION) {
				mCheckedState[position] = isChecked;
			}
		}
	};

	/**
	 * Displaying error message in an AlertDialog
	 * @param msg message to display
	 */
	private void displayErrorMessage(String msg) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(getString(R.string.error));
		builder.setMessage(msg);
		builder.setPositiveButton(R.string.ok, null);
		builder.show();
	}

	/**
	 * Displaying error message in an AlertDialog and exit activity
	 * @param msg message to display
	 */
	private void displayErrorMessageAndFinish(String msg) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(getString(R.string.error));
		builder.setMessage(msg);
		builder.setPositiveButton(R.string.ok, new FinishListener(this));
		builder.show();
	}

}
